#pragma once

#include "stdafx.h"
#include "template/Single.h"
#include <string>
#include "thread/Mutex.h"
#include "thread/Thread.h"
#include "thread/Condition.h"
#include <atomic>

static const char* s_logLevel2String[] =
{
	"TRACE",
	"DEBUG",
	"INFO",
	"WARN",
	"ERROR",
	"FATAL",
};

enum
{
	LOG_LEVEL_TRACE = 0,
	LOG_LEVEL_INFO,
	LOG_LEVEL_DEBUG,
	LOG_LEVEL_WARN,
	LOG_LEVEL_ERROR,
	LOG_LEVEL_FATAL,
	
	LOG_LEVEDL_MAX,
};

struct ConsoleLogColor
{
	char head[32];
	char tail[32];
};

static const ConsoleLogColor s_ConsoleLogColor[] =
{
	"\033[0m", "\033[0m",			//TRACE
	"\033[0m", "\033[0m",			//INFO
	"\033[0m", "\033[0m",			//DEBUG
	"\033[1;33;40m", "\033[0m",		//WARN
	"\033[1;31;40m", "\033[0m",		//ERROR
	"\033[1;31;40m", "\033[0m",		//FATAL
};

class Logger : public Single<Logger>
{
	static const int kMaxFileSize = 1024 * 1024 * 500;	//日志文件最大大小(500M)
	static const int kMaxOneLine = 1024 * 4;		//一行日志最大长度
	static const int kFormatTimeLen = 32;			//格式化时间字符串的长度
	static const int kCheckFileExits = 3;			//3秒检测一次文件是否存在
	
	friend Single<Logger>;
	
public:
	~Logger();

	bool Init(const std::string& path, const std::string& name, int logLevel, const std::string& codeHomePath, bool isLogConsole = true);

	void WriteLog(int logLev, const char* file, int line, const char* function, const char* fmt, ...);

	int GetLevel() const { return m_level; }

private:
	struct LogContext
	{
		std::string msg;
		int level;
	};
	

private:
	Logger();

	FILE* OpenLogFile();

	int CloseLogFile();

	void FlushFile() { assert(m_fp); fflush(m_fp); }

	void FormatTime(time_t t);

	//检测文件是否存在
	bool CheckFileExits();

	//刷新文件:跨天或者文件写满时,新建一个文件.
	void FlushLogFile();

	//日志线程函数:将缓存中的日志消息写入到磁盘文件.
	void WriteFile();

private:
	FILE* m_fp;
	bool m_isInit;
	bool m_isLogConsole;			//输出到控制台
	int m_curSize;					//文件已写入大小
	int m_level;					//日志等级
	std::string m_filePath;			//文件路径
	std::string m_fileName;			//文件名
	std::string m_curFilePath;		//当前文件全名
	std::string m_codeHomePath;		//代码主目录
	int m_fillFileNum;				//已写满文件数
	// char m_line[kMaxOneLine];
	std::queue<LogContext> m_cacheq;	//日志缓存队列
	time_t m_lastSec;
	chaos::Thread m_thread;			//日志写入磁盘线程
	std::atomic<bool> m_working;	//控制写入线程工作
	std::atomic<bool> m_writting;	//正在写入磁盘
	Mutex m_mutex;
	Condition m_cond;

	//only logger thread
	char m_formatTime[32];
	time_t m_lastCheckFile;
};


#define LOG_TRACE(fmt, ...) \
if(LOG_LEVEL_TRACE >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_TRACE, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}

#define LOG_INFO(fmt, ...) \
if(LOG_LEVEL_INFO >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}

#define LOG_DEBUG(fmt, ...) \
if(LOG_LEVEL_DEBUG >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}

#define LOG_WARN(fmt, ...) \
if(LOG_LEVEL_WARN >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_WARN, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}

#define LOG_ERROR(fmt, ...) \
if(LOG_LEVEL_ERROR >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_ERROR,__FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}

#define LOG_FATAL(fmt, ...) \
if(LOG_LEVEL_FATAL >= Logger::Instance().GetLevel()) \
{ \
	Logger::Instance().WriteLog(LOG_LEVEL_FATAL, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__); \
}
